﻿import Data.Char (ord, chr) 				--импорт функций ord и chr из пакета Data.Char
import Data.Ix (inRange) 					--импорт функции inRange из пакета Data.Ix
 
caesar :: Int -> String -> String 			--объявление функции caesar принимающей на вход Int и String и возвращающая String
caesar k = map f 							--определение функции caesar (k - входной параметр (на сколько сдвиг будет),
											--map - функция, которая принимает на вход функцию (у нас это f)
											--и список элементов, а возвращает список элементов, к которому применена данная функция
											--те у нас она выполняет функцию f для каждого символа введенной строки
  where
    f c 									--определение функции f, на вход передается Char с - это как раз таки каждый элемент строки
      | inRange ('a','z') c = tr 'a' k c  	--в зависимости от регистра с, f присваивается значение выполнения функции tr от разных параметров
      | inRange ('A','Z') c = tr 'A' k c
      | otherwise = c						--если с не является английской буквой, то все так и оставляем
unCaesar :: Int -> String -> String 		--объявление функции caesar принимающей на вход Int и String и возвращающая String
unCaesar k = caesar (-k)					--определение функции caesar - функция cesar с обратным значение сдвига
 
                                                                    
tr :: Char -> Int -> Char -> Char 			--объявление функции tr принимающей на вход Char, Int и Char и возвращающей Char
tr base offset char = chr $ ord base + (ord char - ord base + offset) `mod` 26  --определение функции tr - собственно расчет буквы со сдвигом
-- base - Char 'a' или 'A' в зависимости от входного регистра, offset - Int значение сдвига, char - Char символ из нашей строки 
-- chr - делает из Int Char, ord - делает из Char Int
--символ доллара используется, что бы избегать скобок в сложных выражениях избегать скобок, те a $ b + c эквивалентно a (b + c)